import {
  _decorator,
  Enum,
  EventTouch,
  Sprite,
  Node,
  Label,
  builtinResMgr,
  Material,
  SpriteFrame,
  UITransform,
  Color,
  EventMouse,
  lerp,
  NodeEventType,
  TransformBit,
  UIRenderer,
  Vec3,
  XrUIPressEventType,
  Component,
  EventHandler,
  Button,
  __private,
} from 'cc';
import { EventManager } from '../Manager/EventManager';
import { BaseEventType } from '../Config/BaseEnum';
import { TimeConst } from '../../Util/DateUtil';
import { EDITOR, EDITOR_NOT_IN_PREVIEW } from 'cc/env';
const { ccclass, property, menu, executeInEditMode, requireComponent, executionOrder } = _decorator;
/* eslint-disable */
enum ClickType {
  /**正常点击 */
  NORMAL,
  /** 双击 */
  DOUBLE_CLICK,
  /** 长按 */
  LONG_CLICK,
  /** 禁止连续点击 */
  NO_MORE_CLICK_END,
}

enum State {
  NORMAL = 'normal',
  HOVER = 'hover',
  PRESSED = 'pressed',
  DISABLED = 'disabled',
}
const _tempColor = new Color();

@ccclass('ButtonRedefine')
@menu('myComponent/ButtonRedefine')
@requireComponent(UITransform)
@executionOrder(110)
@executeInEditMode
export class ButtonRedefine extends Component {
  /**
   * @en
   * Transition target.<br/>
   * When Button state changed:
   * - Button.Transition.NONE   // Button will do nothing
   * - Button.Transition.COLOR  // Button will change target's color
   * - Button.Transition.SPRITE // Button will change target Sprite's sprite
   * - Button.Transition.SCALE  // Button will change target node's scale
   *
   * @zh
   * 需要过渡的目标。<br/>
   * 按钮可以通过修改 Transition 来设置按钮状态过渡的方式：
   * - Button.Transition.NONE   // 不做任何过渡
   * - Button.Transition.COLOR  // 进行颜色之间过渡
   * - Button.Transition.SPRITE // 进行 Sprite 之间的过渡
   * - Button.Transition.SCALE // 进行缩放过渡
   */
  @property({
    type: Node,
    displayOrder: 0,
    tooltip: '指定背显节点，状态改变时会修改此节点的Color或Sprilte属性',
  })
  get target(): Node {
    return this._target || this.node;
  }

  set target(value) {
    if (this._target === value) {
      return;
    }
    if (this._target) {
      // need to remove the old target event listeners
      this._unregisterTargetEvent(this._target);
    }
    this._target = value;
    this._applyTarget();
  }

  /**
   * @en
   * Whether the Button is disabled.
   * If true, the Button will trigger event and do transition.
   *
   * @zh
   * 按钮事件是否被响应，如果为 false，则按钮将被禁用。
   */
  @property({
    displayOrder: 1,
    tooltip: '按钮是否可交互，这一项未选中时，按钮处在禁用状态',
  })
  get interactable(): boolean {
    return this._interactable;
  }

  set interactable(value) {
    if (this._interactable == value) return;
    if (this.grayscale) {
      const material = builtinResMgr.get<Material>('ui-sprite-gray-material');
      this._findGrayObj(this.node, material, value);
    }

    this._interactable = value;
    this._updateState();

    if (!this._interactable) {
      this._resetState();
    }
  }

  /**
   * @deprecated since v3.7.0, this is an engine private interface that will be removed in the future.
   */
  set _resizeToTarget(value: boolean) {
    if (value) {
      this._resizeNodeToTargetNode();
    }
  }

  /**
   * @en
   * Transition type.
   *
   * @zh
   * 按钮状态改变时过渡方式。
   */
  @property({
    type: Enum(Button.Transition),
    displayOrder: 2,
    tooltip: '按钮状态变化时的过渡类型',
  })
  get transition(): __private._cocos_ui_button__Transition {
    return this._transition;
  }

  set transition(value: __private._cocos_ui_button__Transition) {
    if (this._transition === value) {
      return;
    }

    // Reset to normal data when change transition.
    if (this._transition === Button.Transition.COLOR) {
      this._updateColorTransition(State.NORMAL);
    } else if (this._transition === Button.Transition.SPRITE) {
      this._updateSpriteTransition(State.NORMAL);
    }
    this._transition = value;
    this._updateState();
  }

  // color transition

  /**
   * @en
   * Normal state color.
   *
   * @zh
   * 普通状态下按钮所显示的颜色。
   */
  @property({
    type: Color,
    displayOrder: 3,
    tooltip: '普通状态的按钮背景颜色',
    visible() {
      return this._transition === Button.Transition.COLOR;
    },
  })
  // @constget
  get normalColor(): Readonly<Color> {
    return this._normalColor;
  }

  set normalColor(value) {
    if (this._normalColor === value) {
      return;
    }

    this._normalColor.set(value);
    this._updateState();
  }

  /**
   * @en
   * Pressed state color.
   *
   * @zh
   * 按下状态时按钮所显示的颜色。
   */
  @property({
    type: Color,
    displayOrder: 3,
    tooltip: '按下状态的按钮背景颜色',
    visible() {
      return this._transition === Button.Transition.COLOR;
    },
  })
  // @constget
  get pressedColor(): Readonly<Color> {
    return this._pressedColor;
  }

  set pressedColor(value) {
    if (this._pressedColor === value) {
      return;
    }

    this._pressedColor.set(value);
  }

  /**
   * @en
   * Hover state color.
   *
   * @zh
   * 悬停状态下按钮所显示的颜色。
   */
  @property({
    type: Color,
    displayOrder: 3,
    tooltip: '悬停状态的按钮背景颜色',
    visible() {
      return this._transition === Button.Transition.COLOR;
    },
  })
  // @constget
  get hoverColor(): Readonly<Color> {
    return this._hoverColor;
  }

  set hoverColor(value) {
    if (this._hoverColor === value) {
      return;
    }

    this._hoverColor.set(value);
  }
  /**
   * @en
   * Disabled state color.
   *
   * @zh
   * 禁用状态下按钮所显示的颜色。
   */
  @property({
    type: Color,
    displayOrder: 3,
    tooltip: '禁用状态的按钮背景颜色',
    visible() {
      return this._transition === Button.Transition.COLOR;
    },
  })
  // @constget
  get disabledColor(): Readonly<Color> {
    return this._disabledColor;
  }

  set disabledColor(value) {
    if (this._disabledColor === value) {
      return;
    }

    this._disabledColor.set(value);
    this._updateState();
  }

  /**
   * @en
   * Color and Scale transition duration.
   *
   * @zh
   * 颜色过渡和缩放过渡时所需时间。
   */
  @property({
    displayOrder: 4,
    tooltip: '当用户点击按钮后，按钮会缩放到一个值，这个值等于Button原始 scale* zoomScale, zoomScale可以为负数',
    visible() {
      return this._transition === Button.Transition.SCALE;
    },
    min: 0,
    max: 10,
  })
  get duration(): number {
    return this._duration;
  }

  set duration(value) {
    if (this._duration === value) {
      return;
    }

    this._duration = value;
  }

  /**
   * @en
   * When user press the button, the button will zoom to a scale.
   * The final scale of the button equals (button original scale * zoomScale)
   * NOTE: Setting zoomScale less than 1 is not adviced, which could fire the touchCancel event
   * if the touch point is out of touch area after scaling.
   * if you need to do so, you should set target as another background node instead of the button node.
   *
   * @zh
   * 当用户点击按钮后，按钮会缩放到一个值，这个值等于 Button 原始 scale * zoomScale。
   * 注意：不建议 zoomScale 的值小于 1, 否则缩放后如果触摸点在触摸区域外, 则会触发 touchCancel 事件。
   * 如果你需要这么做，你应该把 target 设置为另一个背景节点，而不是按钮节点。
   */
  @property({
    displayOrder: 3,
    tooltip: '按钮颜色变化或者缩放变化的过渡时间',
    visible() {
      return this._transition === Button.Transition.SCALE;
    },
  })
  get zoomScale(): number {
    return this._zoomScale;
  }

  set zoomScale(value) {
    if (this._zoomScale === value) {
      return;
    }

    this._zoomScale = value;
  }

  // sprite transition
  /**
   * @en
   * Normal state sprite.
   *
   * @zh
   * 普通状态下按钮所显示的 Sprite。
   */
  @property({
    type: SpriteFrame,
    displayOrder: 3,
    tooltip: '普通状态的按钮背景图资源',
    visible() {
      return this._transition === Button.Transition.SPRITE;
    },
  })
  get normalSprite(): SpriteFrame | null {
    return this._normalSprite;
  }

  set normalSprite(value: SpriteFrame | null) {
    if (this._normalSprite === value) {
      return;
    }

    this._normalSprite = value;
    const sprite = this.node.getComponent(Sprite);
    if (sprite) {
      sprite.spriteFrame = value;
    }

    this._updateState();
  }

  /**
   * @en
   * Pressed state sprite.
   *
   * @zh
   * 按下状态时按钮所显示的 Sprite。
   */
  @property({
    type: SpriteFrame,
    displayOrder: 3,
    tooltip: '按下状态的按钮背景图资源',
    visible() {
      return this._transition === Button.Transition.SPRITE;
    },
  })
  get pressedSprite(): SpriteFrame | null {
    return this._pressedSprite;
  }

  set pressedSprite(value: SpriteFrame | null) {
    if (this._pressedSprite === value) {
      return;
    }

    this._pressedSprite = value;
    this._updateState();
  }

  /**
   * @en
   * Hover state sprite.
   *
   * @zh
   * 悬停状态下按钮所显示的 Sprite。
   */
  @property({
    type: SpriteFrame,
    displayOrder: 3,
    tooltip: '悬停状态的按钮背景图资源',
    visible() {
      return this._transition === Button.Transition.SPRITE;
    },
  })
  get hoverSprite(): SpriteFrame | null {
    return this._hoverSprite;
  }

  set hoverSprite(value: SpriteFrame | null) {
    if (this._hoverSprite === value) {
      return;
    }

    this._hoverSprite = value;
    this._updateState();
  }

  /**
   * @en
   * Disabled state sprite.
   *
   * @zh
   * 禁用状态下按钮所显示的 Sprite。
   */
  @property({
    type: SpriteFrame,
    displayOrder: 3,
    tooltip: '禁用状态的按钮背景图资源',
    visible() {
      return this._transition === Button.Transition.SPRITE;
    },
  })
  get disabledSprite(): SpriteFrame | null {
    return this._disabledSprite;
  }

  set disabledSprite(value: SpriteFrame | null) {
    if (this._disabledSprite === value) {
      return;
    }

    this._disabledSprite = value;
    this._updateState();
  }

  @property({
    type: [EventHandler],
    displayOrder: 20,
    tooltip: '按钮点击事件的列表。先将数量改为1或更多，就可以为每个点击事件设置接受者和处理方法',
  })
  public clickEvents: EventHandler[] = [];
  @property({ serializable: true })
  protected _interactable = true;
  @property({ serializable: true })
  protected _transition = Button.Transition.NONE;
  @property({ serializable: true })
  protected _normalColor: Color = Color.WHITE.clone();
  @property({ serializable: true })
  protected _hoverColor: Color = new Color(211, 211, 211, 255);
  @property({ serializable: true })
  protected _pressedColor: Color = Color.WHITE.clone();
  @property({ serializable: true })
  protected _disabledColor: Color = new Color(124, 124, 124, 255);
  @property({ serializable: true })
  protected _normalSprite: SpriteFrame | null = null;
  @property({ serializable: true })
  protected _hoverSprite: SpriteFrame | null = null;
  @property({ serializable: true })
  protected _pressedSprite: SpriteFrame | null = null;
  @property({ serializable: true })
  protected _disabledSprite: SpriteFrame | null = null;
  @property({ serializable: true })
  protected _duration = 0.1;
  @property({ serializable: true })
  protected _zoomScale = 1.2;
  @property({ serializable: true })
  protected _target: Node | null = null;
  private _pressed = false;
  private _hovered = false;
  private _fromColor: Color = new Color();
  private _toColor: Color = new Color();
  private _time = 0;
  private _transitionFinished = true;
  private _fromScale: Vec3 = new Vec3();
  private _toScale: Vec3 = new Vec3();
  private _originalScale: Vec3 | null = null;
  private _sprite: Sprite | null = null;
  private _targetScale: Vec3 = new Vec3();

  public __preload(): void {
    if (!this.target) {
      this.target = this.node;
    }

    this._applyTarget();
    this._resetState();
  }

  public onEnable(): void {
    // check sprite frames
    //
    if (!EDITOR_NOT_IN_PREVIEW) {
      this._registerNodeEvent();
    } else {
      this.node.on(
        Sprite.EventType.SPRITE_FRAME_CHANGED,
        (comp: Sprite) => {
          if (this._transition === Button.Transition.SPRITE) {
            this._setCurrentStateSpriteFrame(comp.spriteFrame);
          } else {
            // avoid serialization data loss when in no-sprite mode
            this._normalSprite = null;
            this._hoverSprite = null;
            this._pressedSprite = null;
            this._disabledSprite = null;
          }
        },
        this
      );
    }
  }

  public onDisable(): void {
    this._resetState();

    if (!EDITOR_NOT_IN_PREVIEW) {
      this._unregisterNodeEvent();
    } else {
      this.node.off(Sprite.EventType.SPRITE_FRAME_CHANGED);
    }
  }

  public onDestroy(): void {
    if (this.target.isValid) {
      this._unregisterTargetEvent(this.target);
    }
  }

  protected _resizeNodeToTargetNode(): void {
    if (!this.target) {
      return;
    }
    const targetTrans = this.target._uiProps.uiTransformComp;
    if (EDITOR && targetTrans) {
      this.node._uiProps.uiTransformComp!.setContentSize(targetTrans.contentSize);
    }
  }

  protected _resetState(): void {
    this._pressed = false;
    this._hovered = false;
    // Restore button status
    const target = this.target;
    if (!target) {
      return;
    }
    const transition = this._transition;
    if (transition === Button.Transition.COLOR && this._interactable) {
      const renderComp = target.getComponent(UIRenderer);
      if (renderComp) {
        renderComp.color = this._normalColor;
      }
    } else if (transition === Button.Transition.SCALE && this._originalScale) {
      target.setScale(this._originalScale);
    }
    this._transitionFinished = true;
  }

  protected _registerNodeEvent(): void {
    this.node.on(NodeEventType.TOUCH_START, this._onTouchBegan, this);
    this.node.on(NodeEventType.TOUCH_MOVE, this._onTouchMove, this);
    this.node.on(NodeEventType.TOUCH_END, this._onTouchEnded, this);
    this.node.on(NodeEventType.TOUCH_CANCEL, this._onTouchCancel, this);

    this.node.on(NodeEventType.MOUSE_ENTER, this._onMouseMoveIn, this);
    this.node.on(NodeEventType.MOUSE_LEAVE, this._onMouseMoveOut, this);

    if (XrUIPressEventType) {
      this.node.on(XrUIPressEventType.XRUI_HOVER_ENTERED, this._xrHoverEnter, this);
      this.node.on(XrUIPressEventType.XRUI_HOVER_EXITED, this._xrHoverExit, this);
      this.node.on(XrUIPressEventType.XRUI_CLICK, this._xrClick, this);
      this.node.on(XrUIPressEventType.XRUI_UNCLICK, this._xrUnClick, this);
    }
  }

  protected _registerTargetEvent(target): void {
    if (EDITOR_NOT_IN_PREVIEW) {
      target.on(Sprite.EventType.SPRITE_FRAME_CHANGED, this._onTargetSpriteFrameChanged, this);
      target.on(NodeEventType.COLOR_CHANGED, this._onTargetColorChanged, this);
    }
    target.on(NodeEventType.TRANSFORM_CHANGED, this._onTargetTransformChanged, this);
  }

  protected _unregisterNodeEvent(): void {
    this.node.off(NodeEventType.TOUCH_START, this._onTouchBegan, this);
    this.node.off(NodeEventType.TOUCH_MOVE, this._onTouchMove, this);
    this.node.off(NodeEventType.TOUCH_END, this._onTouchEnded, this);
    this.node.off(NodeEventType.TOUCH_CANCEL, this._onTouchCancel, this);

    this.node.off(NodeEventType.MOUSE_ENTER, this._onMouseMoveIn, this);
    this.node.off(NodeEventType.MOUSE_LEAVE, this._onMouseMoveOut, this);

    if (XrUIPressEventType) {
      this.node.off(XrUIPressEventType.XRUI_HOVER_ENTERED, this._xrHoverEnter, this);
      this.node.off(XrUIPressEventType.XRUI_HOVER_EXITED, this._xrHoverExit, this);
      this.node.off(XrUIPressEventType.XRUI_CLICK, this._xrClick, this);
      this.node.off(XrUIPressEventType.XRUI_UNCLICK, this._xrUnClick, this);
    }
  }

  protected _unregisterTargetEvent(target): void {
    if (EDITOR_NOT_IN_PREVIEW) {
      target.off(Sprite.EventType.SPRITE_FRAME_CHANGED);
      target.off(NodeEventType.COLOR_CHANGED);
    }
    target.off(NodeEventType.TRANSFORM_CHANGED);
  }

  protected _getTargetSprite(target: Node | null): Sprite | null {
    let sprite: Sprite | null = null;
    if (target) {
      sprite = target.getComponent(Sprite);
    }
    return sprite;
  }

  protected _applyTarget(): void {
    if (this.target) {
      this._sprite = this._getTargetSprite(this.target);
      if (!this._originalScale) {
        this._originalScale = new Vec3();
      }
      Vec3.copy(this._originalScale, this.target.getScale());
      this._registerTargetEvent(this.target);
    }
  }

  private _onTargetSpriteFrameChanged(comp: Sprite): void {
    if (this._transition === Button.Transition.SPRITE) {
      this._setCurrentStateSpriteFrame(comp.spriteFrame);
    }
  }

  private _setCurrentStateSpriteFrame(spriteFrame: SpriteFrame | null): void {
    if (!spriteFrame) {
      return;
    }
    switch (this._getButtonState()) {
      case State.NORMAL:
        this._normalSprite = spriteFrame;
        break;
      case State.HOVER:
        this._hoverSprite = spriteFrame;
        break;
      case State.PRESSED:
        this._pressedSprite = spriteFrame;
        break;
      case State.DISABLED:
        this._disabledSprite = spriteFrame;
        break;
      default:
        break;
    }
  }

  private _onTargetColorChanged(color: Color): void {
    if (this._transition === Button.Transition.COLOR) {
      this._setCurrentStateColor(color);
    }
  }

  private _setCurrentStateColor(color: Color): void {
    switch (this._getButtonState()) {
      case State.NORMAL:
        this._normalColor = color;
        break;
      case State.HOVER:
        this._hoverColor = color;
        break;
      case State.PRESSED:
        this._pressedColor = color;
        break;
      case State.DISABLED:
        this._disabledColor = color;
        break;
      default:
        break;
    }
  }

  private _onTargetTransformChanged(transformBit: TransformBit): void {
    // update originalScale
    if (TransformBit.SCALE & (transformBit as number) && this._originalScale && this._transition === Button.Transition.SCALE && this._transitionFinished) {
      Vec3.copy(this._originalScale, this.target.getScale());
    }
  }

  protected _onTouchMove(event?: EventTouch): void {
    if (!this._interactable || !this.enabledInHierarchy || !this._pressed) {
      return;
    }
    // mobile phone will not emit _onMouseMoveOut,
    // so we have to do hit test when touch moving
    if (!event) {
      return;
    }

    const touch = event.touch;
    if (!touch) {
      return;
    }

    const hit = this.node._uiProps.uiTransformComp!.hitTest(touch.getLocation(), event.windowId);

    if (this._transition === Button.Transition.SCALE && this.target && this._originalScale) {
      if (hit) {
        Vec3.copy(this._fromScale, this._originalScale);
        Vec3.multiplyScalar(this._toScale, this._originalScale, this._zoomScale);
        this._transitionFinished = false;
      } else {
        this._time = 0;
        this._transitionFinished = true;
        this.target.setScale(this._originalScale);
      }
    } else {
      let state: string;
      if (hit) {
        state = State.PRESSED;
      } else {
        state = State.NORMAL;
      }
      this._applyTransition(state);
    }

    if (event) {
      event.propagationStopped = true;
    }
    if (this.isPierce) {
      event.preventSwallow = true;
    }
  }

  protected _onTouchCancel(event?: EventTouch): void {
    if (!this._interactable || !this.enabledInHierarchy) {
      return;
    }

    this._pressed = false;
    this._updateState();
    if (this.isPierce) {
      event.preventSwallow = true;
    }
  }

  protected _onMouseMoveIn(event?: EventMouse): void {
    if (this._pressed || !this.interactable || !this.enabledInHierarchy) {
      return;
    }
    if (this._transition === Button.Transition.SPRITE && !this._hoverSprite) {
      return;
    }

    if (!this._hovered) {
      this._hovered = true;
      this._updateState();
    }
  }

  protected _onMouseMoveOut(event?: EventMouse): void {
    if (this._hovered) {
      this._hovered = false;
      this._updateState();
    }
  }

  // state handler
  protected _updateState(): void {
    const state = this._getButtonState();
    this._applyTransition(state);
  }

  protected _getButtonState(): string {
    let state = State.NORMAL;
    if (!this._interactable) {
      state = State.DISABLED;
    } else if (this._pressed) {
      state = State.PRESSED;
    } else if (this._hovered) {
      state = State.HOVER;
    }
    return state.toString();
  }

  protected _updateColorTransition(state: string): void {
    const color = this[`${state}Color`];

    const renderComp = this.target?.getComponent(UIRenderer);
    if (!renderComp) {
      return;
    }

    if (EDITOR || state === State.DISABLED.toString()) {
      renderComp.color = color;
    } else {
      this._fromColor = renderComp.color.clone();
      this._toColor = color;
      this._time = 0;
      this._transitionFinished = false;
    }
  }

  protected _updateSpriteTransition(state: string): void {
    const sprite = this[`${state}Sprite`];
    if (this._sprite && sprite) {
      this._sprite.spriteFrame = sprite;
    }
  }

  protected _updateScaleTransition(state: string): void {
    if (!this._interactable) {
      return;
    }

    if (state === State.PRESSED.toString()) {
      this._zoomUp();
    } else {
      this._zoomBack();
    }
  }

  protected _zoomUp(): void {
    // skip before __preload()
    if (!this._originalScale) {
      return;
    }
    Vec3.copy(this._fromScale, this._originalScale);
    Vec3.multiplyScalar(this._toScale, this._originalScale, this._zoomScale);
    this._time = 0;
    this._transitionFinished = false;
  }

  protected _zoomBack(): void {
    if (!this.target || !this._originalScale) {
      return;
    }
    Vec3.copy(this._fromScale, this.target.getScale());
    Vec3.copy(this._toScale, this._originalScale);
    this._time = 0;
    this._transitionFinished = false;
  }

  protected _applyTransition(state: string): void {
    const transition = this._transition;
    if (transition === Button.Transition.COLOR) {
      this._updateColorTransition(state);
    } else if (transition === Button.Transition.SPRITE) {
      this._updateSpriteTransition(state);
    } else if (transition === Button.Transition.SCALE) {
      this._updateScaleTransition(state);
    }
  }

  private _xrHoverEnter(): void {
    this._onMouseMoveIn();
    this._updateState();
  }

  private _xrHoverExit(): void {
    this._onMouseMoveOut();
    if (this._pressed) {
      this._pressed = false;
      this._updateState();
    }
  }

  private _xrClick(): void {
    if (!this._interactable || !this.enabledInHierarchy) {
      return;
    }
    this._pressed = true;
    this._updateState();
  }

  private _xrUnClick(): void {
    if (!this._interactable || !this.enabledInHierarchy) {
      return;
    }

    if (this._pressed) {
      EventHandler.emitEvents(this.clickEvents, this);
      this.node.emit(Button.EventType.CLICK, this);
    }
    this._pressed = false;
    this._updateState();
  }

  @property({ type: Enum(ClickType), displayOrder: 5 })
  private clickType: ClickType = ClickType.NO_MORE_CLICK_END;
  @property({ displayOrder: 1 })
  grayscale: boolean = false;
  @property({ displayOrder: 1, tooltip: '按钮点击后是否穿透' })
  isPierce: boolean = false;
  @property({
    visible() {
      return this.grayscale;
    },
  })
  grayscaleMark: string = '#ignore';
  @property({ displayOrder: 6 })
  private subTime: number = 500;
  @property({ displayOrder: 7 })
  private guide: number = 0;
  @property({ displayOrder: 8 })
  private sound: number = 0;

  private clickTimes = 0;
  private startClickTime = -1;
  private delayClickTime = -1;

  // set interactable(value: boolean) {
  //     if (this._interactable == value) return;
  //     if (this.grayscale) {
  //         const material = builtinResMgr.get<Material>('ui-sprite-gray-material');
  //         this._findGrayObj(this.node, material, value);
  //     }
  //     super.interactable = value;
  // }

  // protected _transition: __private._cocos_ui_button__Transition = Button.Transition.NONE;

  update(dt: number): void {
    const target = this.target;
    if (this._transitionFinished || !target) {
      return;
    }

    if (this._transition !== Button.Transition.COLOR && this._transition !== Button.Transition.SCALE) {
      return;
    }

    this._time += dt;
    let ratio = 1.0;
    if (this._duration > 0) {
      ratio = this._time / this._duration;
    }

    if (ratio >= 1) {
      ratio = 1;
    }

    if (this._transition === Button.Transition.COLOR) {
      const renderComp = target._uiProps.uiComp as UIRenderer;
      Color.lerp(_tempColor, this._fromColor, this._toColor, ratio);
      if (renderComp) {
        renderComp.color = _tempColor;
      }
    } else if (this.transition === Button.Transition.SCALE) {
      target.getScale(this._targetScale);
      this._targetScale.x = lerp(this._fromScale.x, this._toScale.x, ratio);
      this._targetScale.y = lerp(this._fromScale.y, this._toScale.y, ratio);
      target.setScale(this._targetScale);
    }

    if (ratio === 1) {
      this._transitionFinished = true;
    }

    if (this.clickType == ClickType.LONG_CLICK && this.startClickTime > 0) {
      this.startClickTime += dt * TimeConst.Seconds;
      if (this.startClickTime >= this.subTime) {
        this.startClickTime = -1;
        this.onClickActive();
      }
      return;
    }
  }

  private _findGrayObj(obj: Node, material: Material, boo: boolean): void {
    if (obj.name.indexOf(this.grayscaleMark) > -1) return;
    const sp = obj.getComponent(Sprite);
    if (sp) {
      sp.grayscale = !boo;
    } else {
      const lab = obj.getComponent(Label);
      if (lab) {
        lab.customMaterial = boo ? null : material;
      }
    }
    obj.children.forEach((cc) => {
      this._findGrayObj(cc, material, boo);
    });
  }

  protected _onTouchBegan(event?: EventTouch): void {
    if (!this._interactable || !this.enabledInHierarchy) {
      return;
    }
    switch (this.clickType) {
      case ClickType.LONG_CLICK:
        this.startClickTime = new Date().getTime();
        break;
      case ClickType.DOUBLE_CLICK:
        if (this.clickTimes == 0) {
          this.startClickTime = new Date().getTime();
        }
        break;
      case ClickType.NO_MORE_CLICK_END:
        if (this.delayClickTime != -1) this.delayClickTime = new Date().getTime() - this.delayClickTime < this.subTime ? this.delayClickTime : -1;
        if (this.delayClickTime != -1) return;
        break;
    }

    this._pressed = true;
    this._updateState();
    if (event) {
      event.propagationStopped = true;
    }
    if (this.isPierce) {
      event.preventSwallow = true;
    }
  }

  protected _onTouchEnded(event?: EventTouch): void {
    if (!this._interactable || !this.enabledInHierarchy || this.delayClickTime != -1) {
      return;
    }
    let time;
    let boo = true;
    switch (this.clickType) {
      case ClickType.NO_MORE_CLICK_END:
        // time = new Date().getTime() - this.startClickTime;
        // if (time < this.subTime) boo = false;
        this.delayClickTime = new Date().getTime();
        break;
      case ClickType.DOUBLE_CLICK:
        if (this.clickTimes > 0) {
          time = new Date().getTime() - this.startClickTime;
          if (time < this.subTime) boo = false;
          this.clickTimes = 0;
        } else {
          this.clickTimes++;
        }
        break;
      case ClickType.LONG_CLICK:
        this.startClickTime = -1;
        boo = false;
        break;
    }

    if (boo) {
      this.onClickActive(event);
    } else if (event) {
      event.propagationStopped = true;
    }
    if (this.isPierce) {
      event.preventSwallow = true;
    }
  }

  onClickActive(event?: EventTouch) {
    if (this._pressed) {
      EventHandler.emitEvents(this.clickEvents, event);
      this.node.emit(Button.EventType.CLICK, this);
    }
    this._pressed = false;
    this._updateState();

    if (event) {
      event.propagationStopped = true;
    }
    if (this.guide > 0) EventManager.Ins().emit(BaseEventType.GAME_CHECK_GUIDE, this.guide);
  }
}
